package dao

import (
	"database/sql"
	"errors"
	"fmt"
	"github.com/robfig/cron/v3"
	"sync"
	"time"
)

// 这里也可以不使用接口设计(设计成接口灵活一些,便于解耦)
type ITimer interface {
	AddTaskByFunc(taskName, spec string, task func()) (cron.EntryID, error)           //通过函数的方法添加任务 cron.EntryID 标识Cron实例中的条目
	AddTaskByJob(taskName, spec string, job interface{ Run() }) (cron.EntryID, error) //通过接口的方法添加任务
	GetCron(taskName string) (*cron.Cron, bool)                                       //根据taskName获取一个具体的定时任务
	StartTask(taskName string)                                                        // 开始任务
	StopTask(taskName string)                                                         // 停止任务
	Remove(taskName string, id int)                                                   //移除定时任务
	Clear(taskName string)
	Close()
}

// 定时任务
type timer struct {
	taskList map[string]*cron.Cron //定时任务列表
	sync.Mutex
}

// AddTaskByFunc 通过函数的方法添加任务
func (it *timer) AddTaskByFunc(taskName, spec string, task func()) (cron.EntryID, error) {
	it.Lock()
	defer it.Unlock()
	if _, ok := it.taskList[taskName]; !ok {
		it.taskList[taskName] = cron.New()
	}
	id, err := it.taskList[taskName].AddFunc(spec, task)
	it.taskList[taskName].Start()
	return id, err
}

// AddTaskByJob 通过接口的方法添加任务
func (it *timer) AddTaskByJob(taskName, spec string, job interface{ Run() }) (cron.EntryID, error) {
	it.Lock()
	defer it.Unlock()
	if _, ok := it.taskList[taskName]; !ok {
		it.taskList[taskName] = cron.New()
	}
	id, err := it.taskList[taskName].AddJob(spec, job)
	it.taskList[taskName].Start()
	return id, err
}

// GetCron 获取对应taskName的cron 可能会为空
func (it *timer) GetCron(taskName string) (*cron.Cron, bool) {
	it.Lock()
	defer it.Unlock()
	v, ok := it.taskList[taskName]
	return v, ok
}

// StartTask 开始任务
func (it *timer) StartTask(taskName string) {
	it.Lock()
	defer it.Unlock()
	if v, ok := it.taskList[taskName]; ok {
		v.Start()
	}
	return
}

// StopTask 停止任务
func (it *timer) StopTask(taskName string) {
	it.Lock()
	defer it.Unlock()
	if v, ok := it.taskList[taskName]; ok {
		v.Stop()
	}
	return
}

// Remove 根据 taskName,id 删除指定任务
func (it *timer) Remove(taskName string, id int) {
	it.Lock()
	defer it.Unlock()
	if v, ok := it.taskList[taskName]; ok {
		v.Remove(cron.EntryID(id)) // 显示的将int类型的id转换成 cron.EntryID类型的 id
	}
	return
}

// Clear 清空指定的任务
func (it *timer) Clear(taskName string) {
	it.Lock()
	defer it.Unlock()
	if v, ok := it.taskList[taskName]; ok {
		v.Stop()
		delete(it.taskList, taskName)
	}
}

// 释放资源(即:停止 it.taskList中所有的任务)
func (it *timer) Close() {
	it.Lock()
	defer it.Unlock()
	for _, v := range it.taskList {
		v.Stop()
	}
}

// New一个定时任务对象
func newTimerTask() ITimer {
	// 因为是 timer的指针实现了 Timer,所以这里返回一个指针
	return &timer{taskList: make(map[string]*cron.Cron)}
}

func initTimer() {
	if Cfg.Timer.Start {
		t := newTimerTask()
		details := Cfg.Timer.Detail
		for _, detail := range details {
			fmt.Println(detail)
			go func(detail Detail) {
				t.AddTaskByFunc("clearDB", Cfg.Timer.Spec, func() {
					err := ClearTable(db, detail.TableName, detail.CompareField, detail.Interval)
					if err != nil {
						fmt.Println("timer error:", err)
					}
				})
			}(detail)
		}
	}
}

//清理数据库表数据 <tableName>表名,<compareField>比较字段,<interval>间隔
func ClearTable(db *sql.DB, tableName, compareField, interval string) error {
	duration, err := time.ParseDuration(interval)
	if err != nil {
		return err
	}
	if duration < 0 {
		return errors.New("parse duration < 0")
	}
	_, err = db.Exec(fmt.Sprintf("delete from %s where %s < ?", tableName, compareField), time.Now().Add(-duration)) // time.Now().Add(-duration)在当前时间的 duration 之前
	return err
}

